/* 
 * Copyright (C) 2012 UTSChedule
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package utsc.apps.utschedule.util;

import java.lang.ref.WeakReference;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnDismissListener;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.LayerDrawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;

/**
 * A general utility class which provides common utilities in the app.
 *
 */
public class AppUtils {
	private static AppUtils _INSTANCE=new AppUtils();
	
	public static final String TOAST_ADD_COURSE_CANCELLED_STRING="Add course is cancelled.";
	public static final String TOAST_ADD_COURSE_SUCCESSFULLY_STRING="Added course successfully.";
	public static final String TOAST_UPDATE_COURSE_CANCELLED_STRING="Update course is cancelled.";
	public static final String TOAST_UPDATE_COURSE_SUCCESSFULLY_STRING="Updated course successfully.";
	
	public static final String TOAST_ADD_ASSIGNMENT_CANCELLED_STRING="Add assignment is cancelled.";
	public static final String TOAST_ADD_ASSIGNMENT_SUCCESSFULLY_STRING="Added assignment successfully.";
	public static final String TOAST_UPDATE_ASSIGNMENT_CANCELLED_STRING="Update assignment is cancelled.";
	public static final String TOAST_UPDATE_ASSIGNMENT_SUCCESSFULLY_STRING="Updated assignment successfully.";
	
	public static final String TOAST_ADD_EXAM_CANCELLED_STRING="Add exam is cancelled.";
	public static final String TOAST_ADD_EXAM_SUCCESSFULLY_STRING="Added exam successfully.";
	public static final String TOAST_UPDATE_EXAM_CANCELLED_STRING="Update exam is cancelled.";
	public static final String TOAST_UPDATE_EXAM_SUCCESSFULLY_STRING="Updated exam successfully.";
	//ERROR MESSAGES
	//Format: ERROR_{layout section:TITTLE|MESSAGE}_{target}_[action] 
	//e.g.: ERROR_TITLE_COURSE_ADD -> the title of an error message related to course feature with the add function.
	public static final String ERROR_TITLE_COURSE_ADD="ERROR - Add Course Information";
	public static final String ERROR_TITLE_COURSE_UPDATE="ERROR - Edit Course Information";
	public static final String ERROR_MESSAGE_COURSE_COURSECODE="Course Code Cannot be empty!";
	public static final String ERROR_MESSAGE_COURSE_LOCATION="Location Cannot be empty!";
	public static final String ERROR_MESSAGE_COURSE_TIME="Start time must be an hour ahead of End time!";
	
	public static final String ERROR_TITLE_TIMETABLE_ADD="ERROR - Add Timetable Information";
	public static final String ERROR_MESSAGE_TIMETABLE_ADD="Please at least fill in the year and term.";
	public static final String ERROR_MESSAGE_TIMETABLE_TITLE="Timetable Title Cannot be empty!";
	public static final String ERROR_MESSAGE_TIMETABLE_YEAR="Year Cannot be empty!";
	public static final String ERROR_MESSAGE_TIMETABLE_STARTDATE="Start Date cannot be empty!";
	
	public static final String ERROR_TITLE_EXAM_ADD="ERROR - Add Exam Information";
	public static final String ERROR_TITLE_EXAM_UPDATE="ERROR - Update Exam Information";
	public static final String ERROR_MESSAGE_EXAM_TIME="Start time must be an hour ahead of End time!";
	public static final String ERROR_MESSAGE_EXAM_LOCATION="Location Cannot be empty!";
	public static final String ERROR_MESSAGE_EXAM_MAX_EXAM="You cannot have more than 2 exams (midterm & final) for this course.";
	public static final String ERROR_MESSAGE_EXAM_GRADE_SAVED_FAILED="Unable to save/update your exam.";
	
	public static final String ERROR_TITLE_ASSIGNMENT_ADD="ERROR - Add Assignment";
	public static final String ERROR_TITLE_ASSIGNMENT_UPDATE="ERROR - Update Assignment";
	public static final String ERROR_MESSAGE_ASSIGNMENT_TITLE="Title cannot be empty!";
	public static final String ERROR_MESSAGE_ASSIGNMENT_WEIGHT="Weight cannot be 0%!";
	
	public static final String ERROR_MESSAGE_ASSIGNMENT_NOT_FOUND="-Unable to find the details of the given assignment.\n\n-Make sure the assignment is exist in the app.";
	public static final String ERROR_MESSAGE_EXAM_NOT_FOUND="-Unable to find the details of the given exam.\n\n-Make sure the exam is exist in the app.";
	public static final String ERROR_MESSAGE_COURSE_NOT_FOUND="-Unable to find the details of the given course.\n\n-Make sure the course is exist in the app.";
	
	public static final String ERROR_TITLE_GENERIC_NOT_FOUND="ERROR - object not found";
	public static final String ERROR_MESSAGE_GENERIC_TOTAL_LESS="Total cannot be less than your mark!";
	public static final String ERROR_MESSAGE_GENERIC_TOTAL="Total cannot be empty!";
	public static final String ERROR_MESSAGE_GENERIC_MARK="Mark cannot be empty!";
	
	public static final String ERROR_MESSAGE_GENERIC_EMPTY_PARAMERTERIZED="%s cannot be empty!";
	public static final String ERROR_MESSAGE_GENERIC_PARAMERTERIZED="%s cannot be empty!";
	public static final String ERROR_TITLE_GENERIC_PARAMERTERIZED="ERROR - %s";
	
	public static final String LABEL_FORECAST_RESULT="In order to get %s, you need to achieve in minimum:";
	
	public static final int BLACK_WHITE_BRIGHTNESS_THRESHOLD=100;
	public static final int ALPHA=175;
	
	private static final String PRIVATE_LOGIN_PREFERENCES_FILENAME="utschedule_login_preferences";
	private static final String LOGIN_PREF_USERID_KEY="userid";
	private static final String LOGIN_PREF_PASSWORD_KEY="password";
	
	private AppUtils () {
	}
	
	public static AppUtils getInstance() {
		return _INSTANCE;
	}

	/**
	 * Return a {@link LayerDrawable} with a {@link WeakReference} by creating the drawable with the given resource id, top overlay color, and the alpha level.
	 * @param context
	 * @param drawableResID
	 * @param color
	 * @param alphaApplycableIndex
	 * @param alpha
	 * @return
	 */
	public static WeakReference<LayerDrawable> getColorCustomizableDrawable(Context context,int drawableResID, int color, int alphaApplycableIndex, int alpha) {
				 
		LayerDrawable drawable = (LayerDrawable) context.getResources()
				.getDrawable(drawableResID);
		
		drawable.getDrawable(0)
				.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
		if (alphaApplycableIndex>=0) {
			drawable.getDrawable(alphaApplycableIndex).setAlpha(alpha);
		}

		return new WeakReference<LayerDrawable>(drawable);
	}
	
	/**
	 * A utility to create a simple dialog dynamically.
	 * @param context
	 * @param resID
	 * @param title
	 * @param dismissListener
	 * @return
	 * @throws IllegalArgumentException
	 */
	public static Dialog createDialogFromResource(Context context,int resID, String title,OnDismissListener dismissListener) throws IllegalArgumentException{
		if (context==null) {
			throw new IllegalArgumentException("Must supply a valid Context object to create a dialog.");
		}
		
		if (resID<=0) {
			throw new IllegalArgumentException("Must supply a valid layout resource ID.");
		}
		
		Dialog resultDialog= new Dialog(context.getApplicationContext());
		resultDialog.setContentView(resID);
		resultDialog.setOnDismissListener(dismissListener);
		return resultDialog;
	}
	
	/**
	 * Hide the virtual keyboard if necessary.
	 * @param activity
	 * @param textView
	 */
	public static void hideKeyBoard(Activity activity, TextView textView) {
		textView.requestFocus();
		 InputMethodManager imm = (InputMethodManager)activity.getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
	       /* if (keyBoardShown()) {
				imm.toggleSoftInput(0, 0);
			}*/
		 imm.hideSoftInputFromWindow(textView.getWindowToken(), 0);
	    
	}
	
	/**
	 * A handy method to compare two colors' brightness differences.
	 * @param color1
	 * @param color2
	 * @return
	 */
	public static float getBrightnessDifferences(int color1, int color2){
		return getColorBrightness(color1)-getColorBrightness(color2);
	}
	
	/**
	 * A handy method to calculate the brightness of a color.
	 * @param color
	 * @return
	 */
	public static float getColorBrightness(int color) {
		int r = Color.red(color);
		int g = Color.green(color);
		int b = Color.blue(color);

		return ((r * 299) + (g * 587) + (b * 114)) / 1000;
	}
	
	/**
	 * Return true if previously has a login setting stored.
	 * @param context
	 * @return
	 */
	public static boolean hasLoginPreferences(Context context){
		final SharedPreferences prefs = new ObscuredSharedPreferences( 
			    context, context.getSharedPreferences(PRIVATE_LOGIN_PREFERENCES_FILENAME, Context.MODE_PRIVATE) );
		if (prefs.getString(LOGIN_PREF_USERID_KEY, null) != null&&prefs.getString(LOGIN_PREF_PASSWORD_KEY, null) != null) {
			return true;
		}
		return false;
	}
	
	/**
	 * Save the given login settings to a private shared preference.
	 * @param context
	 * @param userid
	 * @param password
	 */
	public static void saveLoginPreferences(Context context,String userid, String password){
		final SharedPreferences prefs = new ObscuredSharedPreferences( 
			    context, context.getSharedPreferences(PRIVATE_LOGIN_PREFERENCES_FILENAME, Context.MODE_PRIVATE) );
		prefs.edit().putString(LOGIN_PREF_USERID_KEY,userid).commit();
		prefs.edit().putString(LOGIN_PREF_PASSWORD_KEY,password).commit();
	}
	
	/**
	 * Return the login settings in the form of string array.
	 * @param context
	 * @return
	 */
	public static String[] getLoginPreferences(Context context) {
		final SharedPreferences prefs = new ObscuredSharedPreferences( 
			    context, context.getSharedPreferences(PRIVATE_LOGIN_PREFERENCES_FILENAME, Context.MODE_PRIVATE) );
		return new String[]{prefs.getString(LOGIN_PREF_USERID_KEY, null), prefs.getString(LOGIN_PREF_PASSWORD_KEY, null)};
	}
	
	/**
	 * Remove the current stored login settings from the private shared preference.
	 * @param context
	 */
	public static void	deleteLoginPreferences(Context context){
		final SharedPreferences prefs = new ObscuredSharedPreferences( 
			    context, context.getSharedPreferences(PRIVATE_LOGIN_PREFERENCES_FILENAME, Context.MODE_PRIVATE) );
		prefs.edit().clear().commit();
	}
	
	public static boolean checkNetworkState(Context context) {
		ConnectivityManager connMgr = (ConnectivityManager) 
        context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        return networkInfo != null && networkInfo.isConnected();
	}
}
